#ifndef ESTRATEGIAALMACENAMIENTOBLOQUES_H_
#define ESTRATEGIAALMACENAMIENTOBLOQUES_H_

#include <list>
#include "EstrategiaAlmacenamiento.h"

namespace Toolkit
{

class EstrategiaAlmacenamientoBloques: public EstrategiaAlmacenamiento
{
public:
    EstrategiaAlmacenamientoBloques(const unsigned long int &tamanoBloque,
    		const bool comprimir = false, const float &porcentajeFragmentacion = 0.25);

    virtual ~EstrategiaAlmacenamientoBloques();

    virtual unsigned long int guardarDato(Almacenamiento &almacenamiento,
            const Dato &dato, const Clave &clave, WrapperComponente &wrapper);

    virtual unsigned long int modificarDato(Almacenamiento &almacenamiento,
            const Dato &dato, const Clave &clave,
            const unsigned long int posicion, WrapperComponente &wrapper);

    virtual bool recuperarDato(Almacenamiento &almacenamiento,
            const unsigned long int posicion, Dato &dato, const Clave &clave,
            WrapperComponente &wrapper);

    virtual void eliminarDato(Almacenamiento &almacenamiento,
            const long unsigned int posicion, Dato &dato, const Clave &clave,
            WrapperComponente &wrapper);

    virtual void recuperarComponente(Almacenamiento &almacenamiento,
            const unsigned long int &posicion, WrapperComponente &wrapper);

    virtual void guardarComponente(Almacenamiento &almacenamiento,
            const unsigned long int &posicion, WrapperComponente &wrapper);

    virtual unsigned long int guardarComponente(Almacenamiento &almacenamiento,
            WrapperComponente &wrapper);

    virtual void eliminarComponente(Almacenamiento &almacenamiento, const unsigned long int &posicion,
        		WrapperComponente &wrapper);

private:

    /**
     * Porcentaje de fragmentacion interna permitido en los bloques del
     * almacenamiento.
     * */
    float porcentajeFragmentacion;

    bool comprimir;

    /**
     * Toma el bloque y la posicion en la que fue insertado, y verifica si hace falta
     * considerarlo como fragmentado, esto eso, si será candidato para futuras inserciones
     * de registros.
     * */
    void controlarFragmentacion(const Bloque &bloque,
            const unsigned long int &posicion, Almacenamiento &almacenamiento);

    /**
     * Agrega el registro al bloque y almacena este ultimo en la posicion dada.
     * Si esta no corresponde al final del archivo, se controla la fragmentacion
     * de ese bloque.
     * */
    void almacenar(Bloque &bloque, Registro *registro, const Clave &clave,
            WrapperComponente &wrapper, Almacenamiento &almacenamiento,
            const long unsigned int &posicion);

    /**
     * Retira de la lista de espacios el correspondiente a la posicion de bloque
     * dada, si es que está presente.
     * */
    void removerIndice(const long unsigned int &posicion,
            Almacenamiento &almacenamiento);

    /**
     * Para ser llamado después de retirar un indice de un bloque.
     * Si el bloque quedó vacío se lo retira del almacenamiento; en caso 
     * contrario se lo actualiza y se controla la fragmentación interna. 
     * */
    void actualizarEliminacionRegistro(Bloque &bloque,
            WrapperComponente &wrapper, Almacenamiento &almacenamiento,
            const long unsigned int &posicion);

    Bloque *nuevoBloque();

};

}

#endif /*ESTRATEGIAALMACENAMIENTOBLOQUES_H_*/
